package me.youline.dataServer.utils;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.springframework.beans.factory.FactoryBean;

public class CloseableHttpClientFactory implements
		FactoryBean<CloseableHttpClient> {
	
	private final int RETRY_COUNT = 2;
	
	@Override
	public CloseableHttpClient getObject() throws Exception {
		LayeredConnectionSocketFactory ssl =  new SSLConnectionSocketFactory(createSSLContentext(),
				SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
		Registry<ConnectionSocketFactory> sfr = RegistryBuilder
				.<ConnectionSocketFactory> create()
				.register("http",
						PlainConnectionSocketFactory.getSocketFactory())
				.register(
						"https",
						ssl != null ? ssl : SSLConnectionSocketFactory
								.getSocketFactory()).build();

		CloseableHttpClient client = HttpClientBuilder
				.create()
				.setConnectionManager(
						new PoolingHttpClientConnectionManager(sfr)).setRetryHandler(new HttpRequestRetryHandler() {
							
							@Override
							public boolean retryRequest(IOException exception, int executionCount,
									HttpContext context) {
								if(executionCount > RETRY_COUNT){
									return false;
								}else{
									return true;
								}
							}
						})
				.setMaxConnTotal(200)
				.setMaxConnPerRoute(100)
				.build();
		return client;
	}

	private SSLContext createSSLContentext() throws KeyManagementException, NoSuchAlgorithmException {
		SSLContext sslcontext;
		sslcontext = SSLContext.getInstance(SSLConnectionSocketFactory.TLS); 
		sslcontext.init(null, getTrustsCerts(), new SecureRandom());
		return sslcontext;
	}

	private TrustManager[] getTrustsCerts() {
		TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
			public X509Certificate[] getAcceptedIssuers() {
				return null;
			}

			public void checkClientTrusted(X509Certificate[] certs,
					String authType) {
			}

			public void checkServerTrusted(X509Certificate[] certs,
					String authType) {
			}
		} };
		return trustAllCerts;
	}

	@Override
	public Class<?> getObjectType() {
		return CloseableHttpClient.class;
	}

	@Override
	public boolean isSingleton() {
		return true;
	}

}
